using System;
// ReSharper disable CheckNamespace

/// <summary>
/// ConfigAttribute 用于标记可配置的字段，允许在类中定义配置选项。
/// 此属性可以应用于字段，以指定配置选项的名称、描述和值约束等详细信息。
/// </summary>
/// <remarks>
/// 此属性在希望为用户提供通过外部配置调整应用程序或游戏的某些参数而不修改代码库的能力时特别有用。
/// 它支持定义最小值和最大值、字符串长度限制、浮点数的小数精度以及配置是否应自动保存更改。
/// 当字段为枚举时，注册为下拉列表
/// 为数值类型，且提供大于`MinValue`的`MaxValue`、`InputMaxLength`未指定时注册为滑块
/// 否则和字符串类型一样注册为输入框
/// 布尔类型注册为按钮
/// </remarks>
[AttributeUsage(AttributeTargets.Field)]
public class ConfigAttribute : Attribute
{
    /// <summary>
    /// 配置项的名称，默认使用被标记的字段的名称
    /// </summary>
    public string ConfigName { get; set; } = string.Empty;
    
    /// <summary>
    /// 配置项的描述
    /// </summary>
    public string Description { get; set; } = string.Empty;
    
    /// <summary>
    /// 允许的最小值
    /// 仅适用于数值类型
    /// </summary>
    public float MinValue { get; set; } = 0f;
    
    /// <summary>
    /// 允许的最大值
    /// </summary>
    public float MaxValue { get; set; } = 0f;
    
    /// <summary>
    /// 注册为输入框，且限制最大输入字符数
    /// </summary>
    public int InputMaxLength { get; set; } = 0;
    
    /// <summary>
    /// 配置字段为浮点数滑块时，限制目标精度
    /// </summary>
    public int FloatDecimalPlaces { get; set; } = 1;
    
    /// <summary>
    /// 在配置变更时持久化
    /// </summary>
    public bool AutoSave { get; set; } = true;
}

/// <summary>
/// EnumDisplayAttribute 用于为枚举成员提供一个自定义的显示名称。此属性可以应用于枚举字段，以指定在用户界面或其他需要友好显示的地方使用的名称。
/// </summary>
/// <remarks>
/// 当应用程序或游戏中的枚举值需要以更直观、用户友好的方式展示时，此属性非常有用。它允许开发者为每个枚举成员设置一个描述性的字符串，该字符串可以用来替代默认的枚举名，在UI元素如下拉菜单或列表中显示。
/// </remarks>
[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayAttribute : Attribute
{
    /// <summary>
    /// 枚举项的显示名称
    /// </summary>
    public string DisplayName { get; }

    public EnumDisplayAttribute(string displayName)
    {
        DisplayName = displayName;
    }
}

/// <summary>
/// OnChangeAttribute 用于标记当特定配置项的值发生变化时应调用的方法。
/// 此属性应用于静态方法，以指定该方法作为配置项更改后的回调处理程序。
/// </summary>
/// <remarks>
/// 当配置管理器检测到某个配置项的值被修改后，
/// 它会查找所有使用 OnChangeAttribute 标记且关联到该配置项名称的方法，
/// 并自动调用它们。这使得开发者可以轻松地响应配置变化，
/// 而无需手动编写事件监听代码。支持为多个配置项指定同一个回调方法，通过在单个方法上多次应用此属性来实现。
/// </remarks>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class OnChangeAttribute : Attribute
{
    /// <summary>
    /// 回调函数所关联的配置项名称，为空则关联所有配置项
    /// </summary>
    public string? ConfigName { get; }

    public OnChangeAttribute()
    {
        ConfigName = null;
    }

    public OnChangeAttribute(string configName)
    {
        ConfigName = configName;
    }
}

/// <summary>
/// ButtonAttribute 用于标记方法，使其可以作为按钮显示在用户界面中。
/// 通过此属性，开发者能够定义一个可交互的按钮，允许用户触发特定的方法。
/// 此属性特别适用于需要为用户提供执行某些操作（如重置设置、应用配置等）的快捷方式时。
/// </summary>
/// <remarks>
/// 当应用于方法时，ButtonAttribute 允许指定按钮的描述、显示文本以及一个可选的唯一键。
/// 这个键主要用于内部引用和区分不同的按钮。使用此属性的方法应当是静态的，并且不接受任何参数。
/// AutoConfigManager 会自动扫描并注册带有此属性的方法，生成对应的UI按钮。
/// </remarks>
[AttributeUsage(AttributeTargets.Method)]
public class ButtonAttribute : Attribute
{
    /// <summary>
    /// 按钮的描述文本，用于在界面中显示关于按钮功能的说明。
    /// </summary>
    public string Description { get; set; }

    /// <summary>
    /// 按钮上显示的文本。
    /// </summary>
    public string ButtonText { get; set; }

    /// <summary>
    /// 按钮的唯一标识键，用于在配置管理中区分不同的按钮。如果未指定，则使用方法名作为默认值。
    /// </summary>
    public string? ButtonKey { get; set; }

    public ButtonAttribute(string description, string buttonText = "按钮", string? buttonKey = null)
    {
        ButtonKey = buttonKey;
        Description = description;
        ButtonText = buttonText;
    }
}